#pragma once

#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
#include "type.h"
#include "diag_engine.h"

// char stream -> token

enum class TokenType
{
    number,      // [0-9]+
    indentifier, // 变量
    kw_int,      // int
    kw_if,       // if
    kw_else,     // else
    plus,        // +
    minus,       // -
    star,        // *
    slash,       // /
    equal,       // =
    l_parent,    // (
    r_parent,    // )
    l_brace,     // {
    r_brace,     // }
    semi,        // ;
    comma,       // ,
    eof          // end of file
};

class Token
{
public:
    TokenType tokenType; // token 的种类
    int row, col;

    int value; // for number

    const char *ptr; // for debug
    int length;

    CType *type; // for built-in type

public:
    void Dump();
    static llvm::StringRef GetSpellingText(TokenType tokenType);
};

class Lexer
{
private:
    DiagEngine &diagEngine;
    llvm::SourceMgr &mgr;

public:
    Lexer(DiagEngine &diagEngine, llvm::SourceMgr &mgr) : diagEngine(diagEngine), mgr(mgr)
    {
        unsigned id = mgr.getMainFileID();
        llvm::StringRef buf = mgr.getMemoryBuffer(id)->getBuffer();
        BufPtr = buf.begin();
        LineHeadPtr = buf.begin();
        BufEnd = buf.end();
        row = 1;
    }
    void NextToken(Token &token);

    void SaveState();
    void RestoreState();

    DiagEngine &GetDiagEngine() const
    {
        return diagEngine;
    }

private:
    struct State
    {
        const char *BufPtr;
        const char *LineHeadPtr;
        const char *BufEnd;
        int row;
    };

private:
    const char *BufPtr;
    const char *LineHeadPtr;
    const char *BufEnd;
    int row;

    State state;
};